/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DLL;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

/**
 *
 * @author WIN7
 */
public class CommonMethods {
    
    
    public static void JoinFilesIntoOrigionalFile(File[] files)
    {
        try 
        {
            String joinName= files[0].getName();
            String stringE0=joinName.split("\\.")[0].toString();
            String stringE1=joinName.split("\\.")[1].toString();
            joinName = stringE0 + "." + stringE1;
            File ofile = new File(joinName);
            FileOutputStream fos;
            FileInputStream fis;
            files = SortName(files);
            byte[] fileBytes;
            int bytesRead = 0;          
                fos = new FileOutputStream(ofile,true);             
                for (File file : files)
                {
                    fis = new FileInputStream(file);
                    fileBytes = new byte[(int) file.length()];
                    try
                    {
                        bytesRead = fis.read(fileBytes, 0,(int)  file.length());
                        assert(bytesRead == fileBytes.length);
                        assert(bytesRead == (int) file.length());
                        fos.write(fileBytes);
                        fos.flush();
                        fileBytes = null;
                        fis.close();
                        fis = null;
                    } 
                    catch (IOException ex) 
                    {
                        return;
                    }

                }
            try 
            {
                fos.close();
            } catch (IOException ex) {
                return;
            }
                fos = null;
        } catch (FileNotFoundException ex) {
            return;
        }
        

    }
    
    public static ArrayList<byte[]> SplitBytesToArrayByte(byte[] data, int bytesize)
    {
        int n = data.length / bytesize;
        
        int mod = data.length - n*bytesize; // so byte cua goi tin cuoi cung.
         if(mod != 0)
         {
             n ++;             
         }
         ArrayList<byte[]> sData = new ArrayList<byte[]>();
         
         int seq = 0;   
         int ack = bytesize;
         
         for(int i=0; i< n; i++)
         {             
             if(i==n-1)
             {
                 byte[] bytes;
                 if (mod != 0)
                 {
                     bytes = new byte[mod];
                 }
                 else
                 {
                     bytes = new byte[bytesize];
                 }
                 bytes = Arrays.copyOfRange(data, seq, data.length - 1); 
                 sData.add(bytes);
             }
             else
             {
                byte[] bytes = new byte[bytesize];
                bytes = Arrays.copyOfRange(data, seq, ack);
                sData.add(bytes);
                seq = ack;
                ack += bytesize;
             }             
         }
         return sData;
    }
    
    
    public static byte[] ConvertFileIntoByteArray(File file)throws IOException
    {

    ByteArrayOutputStream ous = null;
    InputStream ios = null;
    try {
        byte[] buffer = new byte[4096];
        ous = new ByteArrayOutputStream();
        ios = new FileInputStream(file);
        int read = 0;
        while ( (read = ios.read(buffer)) != -1 )
        {
            ous.write(buffer, 0, read);
        }
    } 
    catch(IOException e)
    {
        
    }
    ous.close();
    ios.close();
    return ous.toByteArray();
    }
    
    
    public static void ConvertByteArrayIntoFile(byte[] buff, String filename)
    {
        BufferedOutputStream bs = null;
        try 
        {

            FileOutputStream fs = new FileOutputStream(new File(filename));
            bs = new BufferedOutputStream(fs);
            bs.write(buff);
            bs.close();
            bs = null;

        } 
        catch (Exception e)
        {
            e.printStackTrace();
        }

        if (bs != null) 
            try 
                { 
                    bs.close(); 
                }
            catch (Exception e) {}
    }
    
    
    public static ArrayList<Chunk> Split1FileIntoManyFile(File myfile)// Hàm cắt  1 file thành nhiều file chunk với new size = 512 kb
            //trả về 1 danh sách các thông tun chunk sau khi cắt và mã hóa SHA - 1 
    {
        ArrayList<Chunk> listChunk= new ArrayList<Chunk>();
        
        BufferedInputStream bis=null;
        try 
        {
            bis = new BufferedInputStream(new FileInputStream(myfile));
        } catch (FileNotFoundException ex) {
            return null;
        }

        FileOutputStream out;
        String name = myfile.getName();
        int partCounter = 1;
        int sizeOfFiles = 512 * 1024;// 512 Kb
        byte[] buffer = new byte[sizeOfFiles];
        int tmp = 0;
        try {
            while ((tmp = bis.read(buffer)) > 0)
            {
                File newFile=new File(name+"."+String.format("%01d", partCounter++) + ".chunk");
                newFile.createNewFile();
                out = new FileOutputStream(newFile);
                out.write(buffer,0,tmp);                                
                try 
                {
                    // Tạo cách thông tin chunk và add vào list of chunk đã khởi tạo.
                    Chunk newChunk;
                    newChunk = new Chunk(newFile.length(),newFile.getName(), MaHoaDataSHA(newFile));
                    listChunk.add(newChunk);
                } catch (NoSuchAlgorithmException ex) {
                    return null;
                }
                
                out.close();
            }
             JOptionPane.showMessageDialog(null,"Chia file thành công !!!!");
        } 
        catch (IOException ex) 
        {
            return null;
            
        }
        return listChunk;
    }
    
    
    // hàm mã hóa 1 file theo chuẩn SHA-1 , kết quả trả về là chuỗi mã hóa nếu thành công , nếu ko thì chuỗi trả về null
    public static String MaHoaDataSHA(File fi) throws NoSuchAlgorithmException, IOException
    {
    byte[] result=null ;
    MessageDigest digest = MessageDigest.getInstance("SHA-1");
    InputStream fis;
    try 
    {
    fis = new FileInputStream(fi);
    int n = 0;
    byte[] buffer = new byte[1024];
    while (n != -1)
    {
        n = fis.read(buffer);
        if (n > 0) 
        {
            digest.update(buffer, 0, n);
        }
    }
    fis.close();
    result = digest.digest();
    
    StringBuffer sb = new StringBuffer();
        for (int i = 0; i < result.length; i++)
        {
         sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
        }
 
        return sb.toString();
     
    } 
    catch (FileNotFoundException ex)
    {
            Logger.getLogger(CommonMethods.class.getName()).log(Level.SEVERE, null, ex);
            
    }
    return null;
    
    }
    
    
    // Tính checksum gói tin
    public static long calculateChecksum(byte[] buf) 
    {
    int length = buf.length;
    int i = 0;

    long sum = 0;
    long data;

    // Handle all pairs
    while (length > 1) {
      // Corrected to include @Andy's edits and various comments on Stack Overflow
      data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
      sum += data;
      // 1's complement carry bit correction in 16-bits (detecting sign extension)
      if ((sum & 0xFFFF0000) > 0) {
        sum = sum & 0xFFFF;
        sum += 1;
      }

      i += 2;
      length -= 2;
    }

    // Handle remaining byte in odd length buffers
    if (length > 0) {
      // Corrected to include @Andy's edits and various comments on Stack Overflow
      sum += (buf[i] << 8 & 0xFF00);
      // 1's complement carry bit correction in 16-bits (detecting sign extension)
      if ((sum & 0xFFFF0000) > 0) {
        sum = sum & 0xFFFF;
        sum += 1;
      }
    }

    // Final 1's complement value correction to 16-bits
    sum = ~sum;
    sum = sum & 0xFFFF;
    return sum;

  }

    
    
    // Hàm tạo file torrent , tham số đầu vào là 1 danh sách các chunk
    public static void CreateFileTorrent(ArrayList<Chunk> listChunk) throws IOException    
    {
        if(listChunk!=null)
        {
            int ListSize= listChunk.size();
            String torrentName= listChunk.get(0).chunkName;
            String stringE0=torrentName.split("\\.")[0].toString();
            String stringE1=torrentName.split("\\.")[1].toString();
            torrentName = stringE0 + "." + stringE1 + ".torrent";
            File file = new File(torrentName);
            if (!file.exists()) {
               file.createNewFile();
            }
            FileWriter fw = new FileWriter(file, true);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(ListSize + "\r\n");
            for (Chunk c : listChunk)
            {
                bw.write(c.chunkSize + ":" + c.chunkName + ":" + c.hashValue + "\r\n");
                bw.flush();
            }
            bw.close();
        }
    }
    
    public static ArrayList<Chunk> GetChunksFromTorrent(File torrentfile)
    {
        try {
		ArrayList<Chunk> listChunk = new ArrayList<>();
		FileReader fileReader = new FileReader(torrentfile);
		BufferedReader bufferedReader = new BufferedReader(fileReader);
		String line;
                int listsize = Integer.parseInt( bufferedReader.readLine());
		while ((line = bufferedReader.readLine()) != null) 
                {
                     Long cSize = Long.parseLong(line.split(":")[0].toString());
                     String cName = line.split(":")[1].toString();
                     String chashV = line.split(":")[2].toString();
		     Chunk loadedchunk = new Chunk(cSize, cName, chashV);
                     listChunk.add(loadedchunk);
                }
                
		fileReader.close();
                return listChunk;
		}
        catch (IOException e)
                {                  
			e.printStackTrace();
                        return null;
		}
    }
    
    
    public static List<String> CheckChunksExist(String filename)
    {
        List<String> chunklist = new ArrayList<String>(); ;
        String path = ".";
        String files;
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles(); 
        for (int i = 0; i < listOfFiles.length; i++) 
        {

            if (listOfFiles[i].isFile()) 
            {
                files = listOfFiles[i].getName();
                if (files.endsWith(".chunk") && (files.split("\\.")[0] + "." + files.split("\\.")[1]).equals(filename) )
                {
                    chunklist.add(files);
                }
            }
        }
        return chunklist;
    }
    
    
    // Hàm xửa lý sắp xếp dữ liệu
    public static File[] SortName(File[] files)
    {
        File temp;
        File[] result=null;
        for(int i=0;i<files.length-1;i++)
        {
            for(int j=i+1;j<files.length;j++)
            {
                int namef1= Integer.parseInt(files[i].getName().split("\\.")[2].toString());
                int namef2= Integer.parseInt(files[j].getName().split("\\.")[2].toString());
                if(namef1 > namef2)
                {
                    temp=files[i];
                    files[i]=files[j];
                    files[j]=temp;
                }
            } 
        }
        result=files;
        return result;
    }
    
    
    public static List<ReceivedData> SortReceivedData(List<ReceivedData> datain)
    {
        for(int i=0;i<datain.size()-1;i++)
        {
            for(int j=i+1;j<datain.size();j++)
            {
                if(datain.get(i).seqNum > datain.get(j).seqNum)
                {
                    ReceivedData temp=datain.get(i);
                    datain.set(i,datain.get(j));
                    datain.set(j,temp);
                }
            }
        }
        return datain;
    }
    
    
}
